#pragma once

#include "SocketHelper.hpp"
#include <iostream>

namespace cybertron {
	class AcceptSocket {
	public:
		AcceptSocket(SOCKET s, const union_endpoint &ep) : _socket(s), _endpoint(ep) {};
		~AcceptSocket() {};

		SOCKET _socket;
		union_endpoint _endpoint;
	};

#define _SOCKET_IO_NONE		0
#define _SOCKET_IO_ACCEPT	1
#define _SOCKET_IO_READ		2
#define _SOCKET_IO_WRITE	4
	class SocketIO
	{
	public:
		SocketIO(SOCKET s, const union_endpoint &ep, int flag = _SOCKET_IO_NONE) :_socket(s), _endpoint(ep), _io_flag(flag), _last_active(::time(NULL)) {
			;
		};

		virtual ~SocketIO() {
			if (_socket >= 0) {
				SocketHelper::close(_socket);
				//std::cout << "closing connection: remote ip: " << _endpoint.get_addr().to_string().c_str() << "\n";
			}
		}

		SOCKET get_socket() { return _socket; };

		virtual AcceptSocket *on_accept() { return NULL; };
		virtual int on_read() { _last_active = ::time(NULL); return 0; };
		virtual int on_write() { _last_active = ::time(NULL); return 0; };
		virtual int on_close() { return 0; };

#if 0
		void set_read_flag() { _io_flag |= _SOCKET_IO_READ; };
		void set_write_flag() { _io_flag |= _SOCKET_IO_WRITE; };

		void clear_read_flag() { _io_flag &= ~_SOCKET_IO_READ; };
		void clear_write_flag() { _io_flag &= ~_SOCKET_IO_WRITE; };
#endif

		bool has_read_flag() {
			return ((_io_flag & _SOCKET_IO_READ) != 0) || ((_io_flag & _SOCKET_IO_ACCEPT) != 0);
		};

		bool has_write_flag() {
			return (_io_flag & _SOCKET_IO_WRITE) != 0;
		};

		bool has_accept_flag() {
			return (_io_flag & _SOCKET_IO_ACCEPT) != 0;
		};

		bool is_timeout(time_t now, time_t timeout) {
			if (has_accept_flag()) { //server socket will never timeout
				return false;
			}
			return now - _last_active > timeout;
		};

		std::string get_addr() { return _endpoint.get_addr().to_string(); }
	protected:
		SOCKET _socket;
		union_endpoint _endpoint;
		int _io_flag;
		time_t _last_active;
	};

}